﻿#include "AudioFile.h"
#include "lame.h"

struct WaveHeader {
    char    ChunkID[4];
    quint32 ChunkSize;
    char    Format[4];
};

struct WaveFmt {
    char Subchunk1ID[4];
    quint32 Subchunk1Size;
    quint16 AudioFormat; //如果为PCM，改值为 1
    quint16 NumChannels;  //通道数，单通道=1，双通道=2
    quint32 SampleRate;//采用频率
    quint32 ByteRate;/* ==dwSamplesPerSec*wChannels*uiBitsPerSample/8 */
    quint16 BlockAlign;//==wChannels*uiBitsPerSample/8
    quint16 BitsPerSample;//每个采样点的bit数，8bits=8, 16bits=16
};

struct WaveData {
    char Subchunk2ID[4];       //内容为"data"
    quint32 Subchunk2Size;   //==NumSamples*wChannels*uiBitsPerSample/8
};


AudioFile::AudioFile(const QString &fileName) : file_(fileName), initedMp3_(false), type_(Wav)
{
    if (!file_.open(QIODevice::WriteOnly)) {
        qCritical() << "open temp file failed.";
        return;
    }
    file_.write(QByteArray(44, 0));
    file_.flush();

    QString suffix = QFileInfo(fileName).suffix().toLower();
    if (suffix == "wav") {
        type_ = Wav;
    } else if (suffix == "mp3") {
        type_ = Mp3;
    }
}

AudioFile::~AudioFile()
{

}

void AudioFile::write(const QByteArray &data)
{
    switch (type_) {
    case Wav:
        writeAsWav(data);
        break;
    case Mp3:
        writeAsMp3(data);
        break;
    }
}

void AudioFile::finished()
{
    switch (type_) {
    case Wav:
        finishedWav();
        break;
    case Mp3:
        finishedMp3();
        break;
    }
}

void AudioFile::writeAsWav(const QByteArray &data)
{
    file_.write(data);
}

void AudioFile::finishedWav()
{
    file_.flush();
    file_.seek(0);
    qint64 size = file_.size() - 44;

    WaveHeader waveHeader;
    WaveFmt waveFmt;
    WaveData waveData;

    memcpy(waveHeader.ChunkID, "RIFF", 4);
    memcpy(waveHeader.Format, "WAVE", 4);

    memcpy(waveFmt.Subchunk1ID, "fmt ", strlen("fmt "));
    waveFmt.Subchunk1Size = 16;
    waveFmt.AudioFormat = 1;
    waveFmt.NumChannels = 1;
    waveFmt.SampleRate = 16000;
    waveFmt.BitsPerSample = 16;

    waveFmt.ByteRate = waveFmt.SampleRate * waveFmt.NumChannels * waveFmt.BitsPerSample / 8;
    waveFmt.BlockAlign = waveFmt.NumChannels * waveFmt.BitsPerSample / 8;

    memcpy(waveData.Subchunk2ID, "data", strlen("data"));
    waveData.Subchunk2Size = static_cast<quint32>(size);

    waveHeader.ChunkSize = 36 + waveData.Subchunk2Size;

    file_.write(reinterpret_cast<char*>(&waveHeader), sizeof(waveHeader));
    file_.write(reinterpret_cast<char*>(&waveFmt), sizeof(waveFmt));
    file_.write(reinterpret_cast<char*>(&waveData), sizeof(waveData));

    file_.close();
}

void AudioFile::finishedMp3()
{
    lame_global_flags *ptr = reinterpret_cast<lame_global_flags*>(lameClient_);
    lame_close(ptr);
    lameClient_ = nullptr;
}

QByteArray AudioFile::writeAsMp3(const QByteArray &data)
{
//    static QFile file("test.pcm");
//    if (!file.isOpen()) {
//        file.open(QIODevice::WriteOnly);
//    }
//    file.write(data);
//    file.flush();
    if (!initedMp3_) {
        lameClient_ = lame_init();
        lame_set_in_samplerate(reinterpret_cast<lame_global_flags*>(lameClient_), 16000);
        lame_set_out_samplerate(reinterpret_cast<lame_global_flags*>(lameClient_), 44100);
        lame_set_num_channels(reinterpret_cast<lame_global_flags*>(lameClient_), 2);
        lame_set_brate(reinterpret_cast<lame_global_flags*>(lameClient_), 48);
        lame_init_params(reinterpret_cast<lame_global_flags*>(lameClient_));
        initedMp3_ = true;
    }

    int samples = data.size() / static_cast<int>(sizeof (short int));
    const short int *buffer = reinterpret_cast<const short int*>(data.data());

    QByteArray output(data.size() * 2, 0);
    unsigned char *outputPtr = reinterpret_cast<unsigned char *>(output.data());
    int wroteSize = lame_encode_buffer(reinterpret_cast<lame_global_flags*>(lameClient_),
                                       buffer, buffer, samples,
                                       outputPtr, output.size());
    if (wroteSize == 0)
        return QByteArray();
    QByteArray byteWrite = output.mid(0, wroteSize);
    file_.write(byteWrite);

    return byteWrite;
}











